use super::*;
use crate::Result;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::{RwLock, broadcast};

/// Configuration manager that handles configuration loading, saving, and change notifications
pub struct ConfigManager {
    storage: Arc<dyn ConfigStorage>,
    config: RwLock<AppConfig>,
    change_sender: broadcast::Sender<ConfigChangeEvent>,
    validators: RwLock<HashMap<String, Arc<dyn ConfigValidator>>>,
    default_providers: RwLock<Vec<Arc<dyn DefaultConfigProvider>>>,
}

impl ConfigManager {
    /// Create a new configuration manager with the specified storage
    pub fn new(storage: Arc<dyn ConfigStorage>) -> Self {
        let (change_sender, _) = broadcast::channel(100);
        
        Self {
            storage,
            config: RwLock::new(AppConfig::default()),
            change_sender,
            validators: RwLock::new(HashMap::new()),
            default_providers: RwLock::new(Vec::new()),
        }
    }
    
    /// Create a configuration manager with file storage
    pub fn with_file_storage() -> Result<Self> {
        let storage = Arc::new(FileConfigStorage::with_default_paths()?);
        Ok(Self::new(storage))
    }
    
    /// Create a configuration manager with memory storage (for testing)
    pub fn with_memory_storage() -> Self {
        let storage = Arc::new(MemoryConfigStorage::new());
        Self::new(storage)
    }
    
    /// Initialize the configuration manager by loading existing configuration
    pub async fn initialize(&self) -> Result<()> {
        let loaded_config = self.storage.load().await?;
        let mut config = self.config.write().await;
        *config = loaded_config;
        Ok(())
    }
    
    /// Get the current configuration
    pub async fn get_config(&self) -> AppConfig {
        let config = self.config.read().await;
        config.clone()
    }
    
    /// Get a specific configuration value by key path (e.g., "editor.font_size")
    pub async fn get_value(&self, key: &str) -> Result<Option<serde_json::Value>> {
        let config = self.config.read().await;
        let config_json = serde_json::to_value(&*config)?;
        
        Ok(self.get_nested_value(&config_json, key))
    }
    
    /// Set a specific configuration value by key path
    pub async fn set_value(&self, key: &str, value: serde_json::Value) -> Result<()> {
        // Validate the new value
        self.validate_value(key, &value).await?;
        
        let old_value = self.get_value(key).await?;
        
        // Update the configuration
        {
            let mut config = self.config.write().await;
            let mut config_json = serde_json::to_value(&*config)?;
            self.set_nested_value(&mut config_json, key, value.clone())?;
            *config = serde_json::from_value(config_json)?;
        }
        
        // Save to storage
        self.save().await?;
        
        // Notify listeners of the change
        let change_event = ConfigChangeEvent {
            key: key.to_string(),
            old_value,
            new_value: value,
            timestamp: chrono::Utc::now(),
        };
        
        let _ = self.change_sender.send(change_event);
        
        Ok(())
    }
    
    /// Save the current configuration to storage
    pub async fn save(&self) -> Result<()> {
        let config = self.config.read().await;
        self.storage.save(&*config).await
    }
    
    /// Reload configuration from storage
    pub async fn reload(&self) -> Result<()> {
        let loaded_config = self.storage.load().await?;
        let mut config = self.config.write().await;
        *config = loaded_config;
        Ok(())
    }
    
    /// Reset configuration to defaults
    pub async fn reset_to_defaults(&self) -> Result<()> {
        let default_config = self.get_default_config().await;
        
        {
            let mut config = self.config.write().await;
            *config = default_config;
        }
        
        self.save().await?;
        
        // Notify listeners of the reset
        let change_event = ConfigChangeEvent {
            key: "*".to_string(),
            old_value: None,
            new_value: serde_json::Value::Null,
            timestamp: chrono::Utc::now(),
        };
        
        let _ = self.change_sender.send(change_event);
        
        Ok(())
    }
    
    /// Reset a specific configuration section to defaults
    pub async fn reset_section(&self, section: &str) -> Result<()> {
        let default_config = self.get_default_config().await;
        let default_json = serde_json::to_value(&default_config)?;
        
        if let Some(default_section_value) = self.get_nested_value(&default_json, section) {
            self.set_value(section, default_section_value).await?;
        }
        
        Ok(())
    }
    
    /// Subscribe to configuration changes
    pub fn subscribe_to_changes(&self) -> broadcast::Receiver<ConfigChangeEvent> {
        self.change_sender.subscribe()
    }
    
    /// Add a configuration validator
    pub async fn add_validator(&self, key_pattern: String, validator: Arc<dyn ConfigValidator>) {
        let mut validators = self.validators.write().await;
        validators.insert(key_pattern, validator);
    }
    
    /// Add a default configuration provider
    pub async fn add_default_provider(&self, provider: Arc<dyn DefaultConfigProvider>) {
        let mut providers = self.default_providers.write().await;
        providers.push(provider);
    }
    
    /// Create a backup of the current configuration
    pub async fn create_backup(&self) -> Result<PathBuf> {
        self.storage.create_backup().await
    }
    
    /// List available configuration backups
    pub async fn list_backups(&self) -> Result<Vec<PathBuf>> {
        self.storage.list_backups().await
    }
    
    /// Restore configuration from a backup
    pub async fn restore_backup(&self, backup_path: &PathBuf) -> Result<()> {
        self.storage.restore_backup(backup_path).await?;
        self.reload().await?;
        
        // Notify listeners of the restore
        let change_event = ConfigChangeEvent {
            key: "*".to_string(),
            old_value: None,
            new_value: serde_json::Value::String("restored".to_string()),
            timestamp: chrono::Utc::now(),
        };
        
        let _ = self.change_sender.send(change_event);
        
        Ok(())
    }
    
    /// Clean up old backups
    pub async fn cleanup_backups(&self, keep_count: usize) -> Result<()> {
        self.storage.cleanup_backups(keep_count).await
    }
    
    /// Export configuration to a JSON string
    pub async fn export_config(&self) -> Result<String> {
        let config = self.config.read().await;
        Ok(serde_json::to_string_pretty(&*config)?)
    }
    
    /// Import configuration from a JSON string
    pub async fn import_config(&self, json_data: &str) -> Result<()> {
        let imported_config: AppConfig = serde_json::from_str(json_data)?;
        
        // Validate the imported configuration
        self.validate_config(&imported_config).await?;
        
        {
            let mut config = self.config.write().await;
            *config = imported_config;
        }
        
        self.save().await?;
        
        // Notify listeners of the import
        let change_event = ConfigChangeEvent {
            key: "*".to_string(),
            old_value: None,
            new_value: serde_json::Value::String("imported".to_string()),
            timestamp: chrono::Utc::now(),
        };
        
        let _ = self.change_sender.send(change_event);
        
        Ok(())
    }
    
    /// Get configuration file path
    pub fn get_config_path(&self) -> PathBuf {
        self.storage.get_path()
    }
    
    /// Check if configuration file exists
    pub async fn config_exists(&self) -> Result<bool> {
        self.storage.exists().await
    }
    
    // Private helper methods
    
    /// Get nested value from JSON object using dot notation
    fn get_nested_value(&self, json: &serde_json::Value, key: &str) -> Option<serde_json::Value> {
        let parts: Vec<&str> = key.split('.').collect();
        let mut current = json;
        
        for part in parts {
            match current {
                serde_json::Value::Object(map) => {
                    current = map.get(part)?;
                }
                _ => return None,
            }
        }
        
        Some(current.clone())
    }
    
    /// Set nested value in JSON object using dot notation
    fn set_nested_value(&self, json: &mut serde_json::Value, key: &str, value: serde_json::Value) -> Result<()> {
        let parts: Vec<&str> = key.split('.').collect();
        let mut current = json;
        
        for (i, part) in parts.iter().enumerate() {
            if i == parts.len() - 1 {
                // Last part - set the value
                if let serde_json::Value::Object(map) = current {
                    map.insert(part.to_string(), value);
                    return Ok(());
                } else {
                    return Err(ConfigError::InvalidFormat(
                        format!("Cannot set value at key: {}", key)
                    ).into());
                }
            } else {
                // Intermediate part - navigate or create object
                if let serde_json::Value::Object(map) = current {
                    if !map.contains_key(*part) {
                        map.insert(part.to_string(), serde_json::Value::Object(serde_json::Map::new()));
                    }
                    current = map.get_mut(*part).unwrap();
                } else {
                    return Err(ConfigError::InvalidFormat(
                        format!("Cannot navigate to key: {}", key)
                    ).into());
                }
            }
        }
        
        Ok(())
    }
    
    /// Validate a configuration value
    async fn validate_value(&self, key: &str, value: &serde_json::Value) -> Result<()> {
        let validators = self.validators.read().await;
        
        for (pattern, validator) in validators.iter() {
            if self.key_matches_pattern(key, pattern) {
                let result = validator.validate(key, value);
                if !result.is_valid {
                    return Err(ConfigError::ValidationFailed(
                        result.errors.join(", ")
                    ).into());
                }
            }
        }
        
        Ok(())
    }
    
    /// Validate entire configuration
    async fn validate_config(&self, config: &AppConfig) -> Result<()> {
        let config_json = serde_json::to_value(config)?;
        self.validate_json_recursively("", &config_json).await
    }
    
    /// Recursively validate JSON configuration
    fn validate_json_recursively<'a>(&'a self, prefix: &'a str, json: &'a serde_json::Value) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + Send + 'a>> {
        Box::pin(async move {
            match json {
                serde_json::Value::Object(map) => {
                    for (key, value) in map {
                        let full_key = if prefix.is_empty() {
                            key.clone()
                        } else {
                            format!("{}.{}", prefix, key)
                        };

                        self.validate_value(&full_key, value).await?;
                        self.validate_json_recursively(&full_key, value).await?;
                    }
                }
                _ => {}
            }

            Ok(())
        })
    }
    
    /// Check if a key matches a pattern (supports wildcards)
    fn key_matches_pattern(&self, key: &str, pattern: &str) -> bool {
        if pattern == "*" {
            return true;
        }
        
        if pattern.contains('*') {
            // Simple wildcard matching
            let pattern_parts: Vec<&str> = pattern.split('*').collect();
            let mut key_pos = 0;
            
            for (i, part) in pattern_parts.iter().enumerate() {
                if part.is_empty() {
                    continue;
                }
                
                if let Some(pos) = key[key_pos..].find(part) {
                    if i == 0 && pos != 0 {
                        return false; // Pattern must match from the beginning
                    }
                    key_pos += pos + part.len();
                } else {
                    return false;
                }
            }
            
            true
        } else {
            key == pattern
        }
    }
    
    /// Get default configuration with all providers applied
    async fn get_default_config(&self) -> AppConfig {
        let mut config = AppConfig::default();
        let providers = self.default_providers.read().await;
        
        for provider in providers.iter() {
            let defaults = provider.get_defaults();
            let mut config_json = serde_json::to_value(&config).unwrap();
            
            for (key, value) in defaults {
                if let Ok(()) = self.set_nested_value(&mut config_json, &key, value) {
                    if let Ok(updated_config) = serde_json::from_value(config_json.clone()) {
                        config = updated_config;
                    }
                }
            }
        }
        
        config
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[tokio::test]
    async fn test_config_manager_basic_operations() {
        let manager = ConfigManager::with_memory_storage();
        manager.initialize().await.unwrap();
        
        // Test getting default value
        let font_size = manager.get_value("editor.font_size").await.unwrap();
        assert_eq!(font_size, Some(serde_json::Value::Number(14.into())));
        
        // Test setting value
        manager.set_value("editor.font_size", serde_json::Value::Number(16.into())).await.unwrap();
        
        let updated_font_size = manager.get_value("editor.font_size").await.unwrap();
        assert_eq!(updated_font_size, Some(serde_json::Value::Number(16.into())));
    }
    
    #[tokio::test]
    async fn test_config_change_notifications() {
        let manager = ConfigManager::with_memory_storage();
        manager.initialize().await.unwrap();
        
        let mut receiver = manager.subscribe_to_changes();
        
        // Set a value and check for notification
        manager.set_value("editor.font_size", serde_json::Value::Number(18.into())).await.unwrap();
        
        let change_event = receiver.recv().await.unwrap();
        assert_eq!(change_event.key, "editor.font_size");
        assert_eq!(change_event.new_value, serde_json::Value::Number(18.into()));
    }
}
